package home.sockets.controller.concurrent;

import home.sockets.controller.proxy.ProxyServer;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by IntelliJ IDEA.
 * User: Evgeny
 * Date: 13.01.13
 * Time: 1:20
 * To change this template use File | Settings | File Templates.
 */
public class Checker 
{
    private static final InetSocketAddress GOOGLE_ADDRESS = new InetSocketAddress("google.com", 80);
    private static final int DEFAULT_TIMEOUT = 5000;
    private AtomicInteger count;
    private Collection<ProxyServer> activeServers;
    private Collection<ProxyServer> disabledServers;
    private CheckerListener<ProxyServer> listener;

    public void setService(ExecutorService service)
    {
        this.service = service;
    }

    private ExecutorService service;


    public void check(Collection<ProxyServer> servers, CheckerListener<ProxyServer> listener)
    {
        //service = Executors.newFixedThreadPool(5);
        count = new AtomicInteger(servers.size());
        if (!servers.isEmpty())
        {
            activeServers = new ArrayBlockingQueue<>(servers.size());
            disabledServers = new ArrayBlockingQueue<>(servers.size());
            this.listener = listener;
            for (ProxyServer server: servers)
            {
                CheckSocketAction action = new CheckSocketAction(server);
                service.submit(action);
            }
        }
        System.out.println("All sockets have been launched");
    }

    public Collection<ProxyServer> getActiveServers()
    {
        return activeServers;
    }

    public Collection<ProxyServer> getDisabledServers()
    {
        return disabledServers;
    }

    public boolean isDone()
    {
        return count.get() == 0;
    }

    private void handleSocketAction(ProxyServer server, boolean isSuccessful)
    {
        if (isSuccessful)
        {
            activeServers.add(server);
            if (listener != null)
                listener.doAction(server);
        }
        else
            disabledServers.add(server);

        if (count.decrementAndGet() == 0)
            System.out.println("All servers have been checked");
            service.shutdownNow();
    }


    private class CheckSocketAction implements Runnable
    {
        private ProxyServer server;


        CheckSocketAction(ProxyServer server)
        {
            this.server = server;
        }

        @Override
        public void run()
        {
            try
            {
                System.out.println("Start checking " + server.getIp() + ":" + server.getPort());
                Proxy proxy = new Proxy(Proxy.Type.SOCKS,
                        new InetSocketAddress(server.getIp(), Integer.parseInt(server.getPort())));
                Socket socket = new Socket(proxy);
                long start = System.currentTimeMillis();
                socket.connect(GOOGLE_ADDRESS, DEFAULT_TIMEOUT);
                long end = System.currentTimeMillis();
                server.setPing("" + (end - start));
                System.out.println(server.getIp() + ":" + server.getPort() + " connected");
                handleSocketAction(server, true);

            }
            catch(Exception ex)
            {
                System.out.printf("Server %s failed checking, reason %s%n", server, ex);
                handleSocketAction(server, false);
            }
        }
    }

}
